# ------------------------------- Base Setting BEGIN --------------------------------
# 查看PowerShell版本： $psversiontable
#$ps_version = (Get-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\PowerShell\3\PowerShellEngine -Name 'PowerShellVersion').PowerShellVersion
# echo "[Debug] PowerShell Version = $ps_version"

$OsVersion = 0;
# 获取操作系统信息
$os = Get-CimInstance -ClassName Win32_OperatingSystem
$version = [version]$os.Version
# Windows 7 对应版本号为 6.1.*（例如 6.1.7601）。
# Windows 10/11 对应版本号为 10.0.*（例如 10.0.19045）。
# 判断系统版本
# 判断系统版本
if ($version.Major -eq 6) {
    switch ($version.Minor) {
        1 { # 6.1.*
            # Write-Output "Windows 7" 
            $OsVersion = 7;
        }       
        2 { # 6.2.*
            # Write-Output "Windows 8" 
            $OsVersion = 8;
        }       
        3 { # 6.3.*
            # Write-Output "Windows 8.1" 
            $OsVersion = 8.1;
        }    
        default { 
            # Write-Output "其他 Windows 版本: $($os.Caption)" 
            $OsVersion = 0;
        }
    }
} elseif ($version.Major -eq 10) {
    # 通过构建号区分 Win10 和 Win11
    if ($version.Build -ge 22000) {          # Win11 构建号 ≥ 22000
        # Write-Output "Windows 11"
        $OsVersion = 11;
    } else {                                 # Win10 构建号 < 22000
        # Write-Output "Windows 10"
        $OsVersion = 10;
    }
} else {
    # Write-Output "未知系统: $($os.Caption)"
    $OsVersion = 0;
}


# powershell输出的文件时为UTF-16LE格式的
# [使用shell和powershell把文件编码转成UTF-8 NO BOM - 知乎](https://zhuanlan.zhihu.com/p/345246104)

# 生成的文件是UTF-8 WITH BOM。默认powershell5.1默认就是此格式，如果想生成UTF-8 NO BOM，需要采用powershell 7+。
# 设置重定向时编码就会变为UTF-8 BOM
# $PSDefaultParameterValues['Out-File:Encoding'] = 'utf8'
# PowerShell 5.0的版本，进行这样设置后，使用>或>>重定向是不行的，必须通过Out-File命令进行重定向才会生效。

# [Out-File (Microsoft.PowerShell.Utility) - PowerShell | Microsoft Learn](https://learn.microsoft.com/zh-cn/powershell/module/microsoft.powershell.utility/out-file?view=powershell-7.4)

# PowerShell 6+ 之后有可以转UTF-8 NO BOM 这是在PowerShell 5.1的转换
# [关于编码：使用PowerShell以UTF-8编写没有BOM的文件 | 码农家园](https://www.codenong.com/5596982/)
function Out-FileUtf8NoBom {

  [CmdletBinding()]
  param(
    [Parameter(Mandatory, Position=0)] [string] $LiteralPath,
    [switch] $Append,
    [switch] $NoClobber,
    [AllowNull()] [int] $Width,
    [Parameter(ValueFromPipeline)] $InputObject
  )

  #requires -version 3

  # Make sure that the .NET framework sees the same working dir. as PS
  # and resolve the input path to a full path.
  [System.IO.Directory]::SetCurrentDirectory($PWD) # Caveat: .NET Core doesn't support [Environment]::CurrentDirectory
  $LiteralPath = [IO.Path]::GetFullPath($LiteralPath)

  # If -NoClobber was specified, throw an exception if the target file already
  # exists.
  if ($NoClobber -and (Test-Path $LiteralPath)) {
    Throw [IO.IOException]"The file '$LiteralPath' already exists."
  }

  # Create a StreamWriter object.
  # Note that we take advantage of the fact that the StreamWriter class by default:
  # - uses UTF-8 encoding
  # - without a BOM.
  $sw = New-Object IO.StreamWriter $LiteralPath, $Append

  $htOutStringArgs = @{}
  if ($Width) {
    $htOutStringArgs += @{ Width = $Width }
  }

  # Note: By not using begin / process / end blocks, we're effectively running
  #       in the end block, which means that all pipeline input has already
  #       been collected in automatic variable $Input.
  #       We must use this approach, because using | Out-String individually
  #       in each iteration of a process block would format each input object
  #       with an indvidual header.
  try {
    $Input | Out-String -Stream @htOutStringArgs | % { $sw.WriteLine($_) }
  } finally {
    $sw.Dispose()
  }

}

function which ($command) {
  Get-Command -Name $command -ErrorAction SilentlyContinue |
    Select-Object -ExpandProperty Path -ErrorAction SilentlyContinue
}


# 函数 添加系统环境变量
Function Add-EnvVars($AddEnvName,$AddEnvVal,$AddEnvClass) {
                                           # Process 、User 、Machine

    # 获取原来的环境变量
    # $ProcessPathParts = [System.Environment]::GetEnvironmentVariable('PATH', "Process") -Split ";"
    # Write-Host "[INFO] $ProcessPathParts"; # 打印信息
    # $UserPathParts = [System.Environment]::GetEnvironmentVariable('PATH', "User") -Split ";"
    # Write-Host "[INFO] $UserPathParts"; # 打印信息
    # $SysPathParts = [System.Environment]::GetEnvironmentVariable('PATH', "Machine") -Split ";"
    # Write-Host "[INFO] $SysPathParts"; # 打印信息
    # $PathParts = [System.Environment]::GetEnvironmentVariable("${AddEnvName}", "${AddEnvClass}") -Split ";"
    $OrgPathParts = [System.Environment]::GetEnvironmentVariable("${AddEnvName}", "${AddEnvClass}")
    $PathParts = $OrgPathParts -Split ";"
    Write-Host "[INFO] $PathParts"; # 打印信息
    if($PathParts -contains $AddEnvVal) { # 已存在了
    # -contains操作符确实很强大，但是很遗憾，它不能在指定字符串中包含通配符。如果想使用通配符进行查找数组元素，则可以使用-like操作符。
    Write-Host "[INFO] $PathParts  exist $AddEnvVal"; # 打印信息
    } else { # 不存在
    # 
    # Write-Host "[INFO] $AddEnvName isn't exist $AddEnvVal"; # 打印信息
    $NewPathParts = $PathParts + $AddEnvVal
    # Write-Host "[INFO] PathParts = $PathParts "; # 打印信息
    $NewPath = $NewPathParts -Join ";"
    # Write-Host "[INFO] NewPath == $NewPath  "; # 打印信息
    # [System.Environment]::SetEnvironmentVariable("${AddEnvName}", "${AddEnvVal}",  "${AddEnvClass}")
    [System.Environment]::SetEnvironmentVariable("${AddEnvName}", "${NewPath}",  "${AddEnvClass}")
    # [System.Environment]::SetEnvironmentVariable("${AddEnvName}", "${NewPath}",  "Machine") # 系统环境变量无法使用脚本写入 ，提示不允许所请求的注册表访问权。”
    # 添加完再次查询
    $PathParts = [System.Environment]::GetEnvironmentVariable("${AddEnvName}", "${AddEnvClass}") -Split ";"
    Write-Host "[INFO] $PathParts"; # 打印信息
    }

}

## 检查环境变量

if(-Not ($env:PATH.Contains("C:\Tools\bin"))) {
    echo 'C:\Tools\bin not in path, appending environment variable'
    # $env:PATH += ";C:\Tools\bin\";
    Add-EnvVars "PATH" "C:\Tools\bin" "User";
}
if(-Not ($env:PATH.Contains("${env:USERPROFILE}\Documents\XWorkSpaces\my-windows-config\scripts\fsshscp"))) {
    # echo 'C:\Tools\bin not in path, appending environment variable'
    # $env:PATH += ";C:\Tools\bin\";
    Add-EnvVars "PATH" "${env:USERPROFILE}\Documents\XWorkSpaces\my-windows-config\scripts\fsshscp" "User";
}
if(-Not ($env:PATH.Contains("${env:USERPROFILE}\Documents\XWorkSpaces\my-windows-config\scripts\bin"))) {
    # echo 'C:\Tools\bin not in path, appending environment variable'
    # $env:PATH += ";C:\Tools\bin\";
    Add-EnvVars "PATH" "${env:USERPROFILE}\Documents\XWorkSpaces\my-windows-config\scripts\bin" "User";
}
if(-Not ($env:PATH.Contains("C:\Tools\PSTools"))) {
    echo 'C:\Tools\PSTools not in path, appending environment variable';
    # $env:PATH += ";C:\Tools\PSTools\";
    Add-EnvVars "PATH" "C:\Tools\PSTools" "User";
}

# 使用-not运算符判断
if ( -not $(which "pyenv")) { 
    # 不存在
} else {
    # 获取
    # $activeVersion = (pyenv version) -split ' ' | Select-Object -First 1
    $nowPipEnvPath = (pyenv which pip) | Select-Object -First 1
    # Write-Host "当前 Python 版本: $nowPipEnvPath"
    # 构建 Scripts 路径
    # $scriptsPath = 方法一：使用-replace：
    $scriptsPath = $nowPipEnvPath -replace '\\pip\.exe$', ''
    # 方法二：分割数组：
    # $scriptsPathTemp = $nowPipEnvPath -split '\\'
    # $scriptsPath = $scriptsPathTemp[0..($scriptsPathTemp.Length-2)] -join '\'
    # 判断是否已经有了
    if(-Not $env:PATH.Contains("$scriptsPath")){
        $userPathParts = [System.Environment]::GetEnvironmentVariable("PATH", "User") -Split ";"
        # Write-Host "[INFO] userPathParts = $userPathParts"; # 打印信息
        # 分割路径并筛选：移除所有旧版 pyenv Scripts 路径
        $cleanedPaths = $userPathParts -split ';' | Where-Object {
            # 排除空项及所有符合 "pyenv-win\versions\任意子目录\Scripts" 的路径
            ($_ -ne '') -and ($_ -notlike "*pyenv-win\versions\*\Scripts*")
        }
        # Write-Host "[INFO] cleanedPaths = $cleanedPaths"; # 打印信息
        # 判断是否已有其他pip环境变量
        Add-EnvVars "PATH" "$scriptsPath" "User";
    } else {
        # Write-Host "[INFO] $scriptsPath is exist.";
    }
}

# 设置字符集
$env:LESSCHARSET="utf-8"

# 获取当前路径 fsshscp加入环境变量
# ($pwd).Path

# ------------------------------- Base Setting BEGIN --------------------------------

#------------------------------- Auto Download BEGIN --------------------------------

function Invoke-Download
{
    param (
        [Parameter()] [string] $uri = "https://ftp.ncep.noaa.gov/data/nccf/com/hrrr/prod/hrrr.$m2/conus/hrrr.t$m21z.wrfsfcf00.grib2.idx",
        [Parameter()] [string] $outputPath = "C:\OpenGrADS-2.2\data\hrrr\test.grb2",
        [Parameter()] [int] $sleeptimer = 30,
        [Parameter()] [int] $maxTries = 3,
        [Parameter()] [int] $tries = 0
    )
    # 判断是否下载完成存在文件，存在则则不重复下载
    $TRUE_FALSE=(Test-Path $outputPath)
    if($TRUE_FALSE -eq "True")
    {
        # 文件已经存在
        echo "[Info] $outputPath" 
    } else {
        try
        {
            Invoke-WebRequest -Uri $uri -OutFile $outputPath;
        }
        catch [System.Net.WebException]
        {
            $tries++;

            if($tries -lt $maxTries)
            {
                Start-Sleep -Seconds $sleeptimer
                Invoke-Download -uri $uri -outputPath $outputPath -sleeptimer $sleeptimer -maxTries $maxTries -tries $tries
            }
            else
            {
                Write-Error ("Tried to download '{0}' {1}-times and failed" -f $uri, $tries);
            }
        }
    }
}

# 判断是否路径下文件否存在，不存在则进行自动下载解压到对应位置
function file_auto_check_down($name, $download_url, $ouput_path, $expand_archive_path, $rename_type ,   $expand_archive_type, $move_sub_path="" ){
#                             文件名称 下载地址       保存目录       解压目录             下载时保存名字类型 解压方式类型
    #echo "[debug] file_auto_check_down()"
    #echo "[debug] name = $name"
    #echo "[debug] download_url = $download_url"
    #echo "[debug] ouput_path = $ouput_path"
    $file_path = "$expand_archive_path/$name"
    #echo "[debug] file_path = $file_path"
    # 判断是否下载完成存在文件，存在则进行解压
    $TRUE_FALSE=(Test-Path $file_path)
    if($TRUE_FALSE -eq "True") { 
        # 文件存在
        # echo "[debug] It is exits."
    } else {
        # 文件不存在
        # echo "[debug] It is not exits."
        $save_file_name = $download_url.split("/")[-1];
        echo "[debug] save_file_name = $save_file_name";
        echo "[debug] rename_type = $rename_type";
        #$ouput_file_path = "$ouput_path/$name-$save_file_name"
        #echo "[debug] ouput_file_path = $ouput_file_path";
        switch ($rename_type)
        {
            # "string" | number | variable | { <value-scriptblock> } { <action-scriptblock> }
            "0"     { echo "[debug] rename_type = 0." ;$ouput_file_path = "$ouput_path/$save_file_name"  }
            "1"     { echo "[debug] rename_type = 1." ;$ouput_file_path = "$ouput_path/$name-$save_file_name"  }
            default { $ouput_file_path = "$ouput_path/$save_file_name" }  # optional
        }
        echo "[debug] ouput_file_path = $ouput_file_path";
        Invoke-Download $download_url $ouput_file_path;
        # 判断是否下载完成存在文件，存在则进行解压
        $TRUE_FALSE=(Test-Path $ouput_file_path)
        if($TRUE_FALSE -eq "True")
        {

            switch ($expand_archive_type)
            { # 根据不同情况进行解压
                "0" { 
                    # 不用解压，直接拷贝文件到对应目录下
                    # "string" | number | variable | { <value-scriptblock> } { <action-scriptblock> }
                    echo "[debug] expand_archive_type = 0." 
                    # 拷贝文件到对应目录下
                    # $cmd_string="Move-Item -Path $name.exe -Destination $expand_archive_path"
                    $cmd_string="Move-Item -Path $ouput_file_path -Destination $expand_archive_path/$save_file_name"
                    echo echo "[debug] cmd_string = $cmd_string"
                    Invoke-Expression $cmd_string # 执行命令
                }
                "1" { 
                    # 先解压，然后进入一层目录，拷贝文件到对应目录下
                    echo "[debug] expand_archive_type = 1." 
                    Expand-Archive -LiteralPath $ouput_file_path -DestinationPath $ouput_path # 在下载保存目录解压
                    # Move-Item -Path C:\Temp -Destination C:\Logs  # Temp 目录及其所有子目录和文件随后将显示在 Logs 目录下
                    echo "[debug] save_file_name = $save_file_name ." 
                    $expand_archive_file_name = ("$save_file_name" -split ".zip")[0]
                    echo "[debug] expand_archive_file_name = $expand_archive_file_name ." 
                    switch ($rename_type)
                    {
                        # "string" | number | variable | { <value-scriptblock> } { <action-scriptblock> }
                        "1"     { echo "[debug] rename_type = 1." ;$expand_archive_file_path = "$ouput_path/$name-$expand_archive_file_name"  }
                        default { $expand_archive_file_path = "$ouput_path/$expand_archive_file_name" }  # optional
                    }
                    if ($move_sub_path)
                    {
                        Write-Host "The variable is not null."
                        $expand_archive_file_path = "$expand_archive_file_path/$move_sub_path"
                    }
                    else{
                        Write-Host "The variable is null."
                    }
                    echo "[debug] expand_archive_file_path = $expand_archive_file_path ." 
                    # 拷贝文件到对应目录下
                    $cmd_string="Move-Item -Path $expand_archive_file_path\* -Destination $expand_archive_path"
                    echo echo "[debug] cmd_string = $cmd_string"
                    Invoke-Expression $cmd_string # 执行命令
                    # 删除下载和解压的文件

                }
                default { 
                    # 直接解压到对应目录下 
                    echo "[debug] expand_archive_type = 1."   
                    # Expand-Archive -LiteralPath C:\Temp\Temp_Files.Zip -DestinationPath C:\Temp
                    Expand-Archive -LiteralPath $ouput_file_path -DestinationPath $expand_archive_path
                    # [Expand-Archive (Microsoft.PowerShell.Archive) - PowerShell | Microsoft Learn](https://learn.microsoft.com/zh-cn/powershell/module/microsoft.powershell.archive/expand-archive?view=powershell-7.4)
                    # 删除文件
                    # remove-Item -Recurse -Force $ouput_file_path
                }  # optional
            }
        }
    }

}

# 判断是否命令行工具是否存在，不存在则进行自动下载解压到对应位置
function cmd_tool_auto_check_down($name, $download_url, $ouput_path, $expand_archive_path, $move_sub_path="" ){
#                                命令名称 下载地址        保存目录       解压目录
    #echo "[debug] name = $name"
    #echo "[debug] download_url = $download_url"
    #echo "[debug] ouput_path = $ouput_path"
    $cmd_path = $(which $name)
    #echo "[debug] cmd_path = $cmd_path"
    # 使用-not运算符判断
    if ( -not $cmd_path) { 
        # 字符串为空
        # echo "[debug] It is empty.";
        # $save_file_name = "$name.zip"
        $save_file_name = $download_url.split("/")[-1];
        # echo "[debug] save_file_name = $save_file_name";
        $ouput_file_path = "$ouput_path/$save_file_name";
        # echo "[debug] ouput_file_path = $ouput_file_path";
        Invoke-Download $download_url $ouput_file_path;
        # 判断是否下载完成存在文件，存在则进行解压
        $TRUE_FALSE=(Test-Path $ouput_file_path)
        if($TRUE_FALSE -eq "True")
        {
            # Expand-Archive -LiteralPath C:\Temp\Temp_Files.Zip -DestinationPath C:\Temp
            Expand-Archive -LiteralPath $ouput_file_path -DestinationPath $expand_archive_path

            # 如果后面还有这个参数不为空则在进行一次移动
            # 使用-not运算符判断
            if ( -not $move_sub_path) { 
                # 字符串为空
                echo  "[INFO] It is empty."
            } else {
                # 拷贝文件到对应目录下
                $move_origin_file_path = "$expand_archive_path/$move_sub_path"
                $cmd_string="Move-Item -Path $move_origin_file_path\* -Destination $expand_archive_path"
                echo  "[INFO] cmd_string = $cmd_string"
                Invoke-Expression $cmd_string # 执行命令
                # 删除文件
                # remove-Item -Recurse -Force $move_origin_file_path
                $cmd_string="remove-Item -Recurse -Force $move_origin_file_path"
                echo "[INFO] cmd_string = $cmd_string"
                Invoke-Expression $cmd_string # 执行命令
            }

            # 删除文件
            # remove-Item -Recurse -Force $ouput_file_path
        }
    } else {
        # 字符串不为空
        # echo "[debug] It is not empty."
    }
}

# 自动下载脚本或文件到指定位置
# $(file_auto_check_down "z.lua" "https://github.moeyy.xyz/https://github.com/skywind3000/z.lua/archive/refs/tags/1.8.17.zip" "$HOME\Downloads" "C:\Tools\z.lua"  "1" "1")
$(file_auto_check_down "z.lua" "https://github.moeyy.xyz/https://github.com/skywind3000/z.lua/archive/refs/tags/1.8.20.zip" "$HOME\Downloads" "C:\Tools\z.lua"  "1" "1")
# $(file_auto_check_down "pyenv" "https://github.moeyy.xyz/https://github.com/pyenv/pyenv/archive/refs/tags/v2.4.16.zip" "$HOME\Downloads" "C:\Tools\pyenv"  "1" "1")
if ($OsVersion -eq 7) {
    # 注 如果是win7系统，ffmpeg不要用最新版本，可用4.4版本
    # [ffmpeg Old Versions Downloads - VideoHelp](https://www.videohelp.com/software/ffmpeg/old-versions)
    # https://www.videohelp.com/download/ffmpeg-4.4-full_build.7z
} else {
    $(file_auto_check_down "ffmpeg.exe" "https://github.moeyy.xyz/https://github.com/BtbN/FFmpeg-Builds/releases/download/latest/ffmpeg-master-latest-win64-lgpl.zip" "$HOME\Downloads" "C:\Tools\bin" "0" "1" "bin")
}
$(file_auto_check_down "zip.exe" "http://stahlworks.com/dev/zip.exe" "$HOME\Downloads" "C:\Tools\bin" "0" "0" )
$(file_auto_check_down "unzip.exe" "http://stahlworks.com/dev/unzip.exe" "$HOME\Downloads" "C:\Tools\bin" "0" "0" )
$(file_auto_check_down "Readest_0.9.23_x64-portable.exe" "https://github.moeyy.xyz/https://github.com/readest/readest/releases/download/v0.9.23/Readest_0.9.23_x64-portable.exe" "$HOME\Downloads" "C:\Tools\bin" "0" "0" )
$(file_auto_check_down "yt-dlp.exe" "https://github.moeyy.xyz/https://github.com/yt-dlp/yt-dlp/releases/download/2025.02.19/yt-dlp.exe" "$HOME\Downloads" "C:\Tools\bin" "0" "0" )
$(file_auto_check_down "glint-windows" "https://github.moeyy.xyz/https://github.com/brigand/glint/releases/download/v6.3.4/glint-windows" "$HOME\Downloads" "C:\Tools\bin" "0" "0" )
$(file_auto_check_down "Wave-win32-x64-0.11.2.exe" "https://github.moeyy.xyz/https://github.com/wavetermdev/waveterm/releases/download/v0.11.2/Wave-win32-x64-0.11.2.exe" "$HOME\Downloads" "C:\Tools\bin" "0" "0" )
# 对比工具
$(file_auto_check_down "windows_czkawka_cli.exe" "https://github.moeyy.xyz/https://github.com/qarmin/czkawka/releases/download/9.0.0/windows_czkawka_cli.exe" "$HOME\Downloads" "C:\Tools\bin" "0" "0" )
#
$(file_auto_check_down "7zr.exe" "https://www.7-zip.org/a/7zr.exe" "$HOME\Downloads" "C:\Tools\bin"  "0" "0" )


# $(file_auto_check_down "fd.exe" "https://github.moeyy.xyz/https://github.com/sharkdp/fd/releases/download/v10.1.0/fd-v10.1.0-x86_64-pc-windows-msvc.zip" "$HOME\Downloads" "C:\Tools\bin" "1" "1" )




# 自动下载安装命令工具
$(cmd_tool_auto_check_down "fzf" "https://github.moeyy.xyz/https://github.com/junegunn/fzf/releases/download/0.46.1/fzf-0.46.1-windows_amd64.zip" "$HOME\Downloads" "C:\Tools\bin")
# 注 win7系统不支持--height 特性，配置中需要去除
# $(cmd_tool_auto_check_down "BBDown" "https://github.moeyy.xyz/https://github.com/nilaoda/BBDown/releases/download/1.6.1/BBDown_1.6.1_20230818_win-x64.zip" "$HOME\Downloads" "C:\Tools\bin")
$(cmd_tool_auto_check_down "BBDown" "https://github.moeyy.xyz/https://github.com/nilaoda/BBDown/releases/download/1.6.3/BBDown_1.6.3_20240814_win-x64.zip" "$HOME\Downloads" "C:\Tools\bin")

$(cmd_tool_auto_check_down "lux" "https://github.moeyy.xyz/https://github.com/iawia002/lux/releases/download/v0.24.1/lux_0.24.1_Windows_x86_64.zip" "$HOME\Downloads" "C:\Tools\bin")

$(cmd_tool_auto_check_down "bat" "https://github.moeyy.xyz/https://github.com/sharkdp/bat/releases/download/v0.25.0/bat-v0.25.0-x86_64-pc-windows-gnu.zip" "$HOME\Downloads" "C:\Tools\bin" "bat-v0.25.0-x86_64-pc-windows-gnu")

$(cmd_tool_auto_check_down "termscp" "https://github.moeyy.xyz/https://github.com/veeso/termscp/releases/download/v0.16.1/termscp-v0.16.1-x86_64-pc-windows-msvc.zip" "$HOME\Downloads" "C:\Tools\bin" )

## BBDown 配置
function BBDown_config(){
    #
    $BBDown_config_file_path = "C:\Tools\bin\BBDown.config"
    #echo "[debug] file_path = $file_path"
    # 判断是否下载完成存在文件，存在则进行解压
    $TRUE_FALSE=(Test-Path $BBDown_config_file_path)
    if($TRUE_FALSE -eq "True") { 
        # 文件存在
        # echo "[debug] BBDown_config_file_path It is exits."
    } else {
        # 文件不存在
        #echo "[debug] BBDown_config_file_path It is not exits."
        echo "--work-dir $HOME/Downloads `n --skip-ai False " > "C:\Tools\bin\BBDown.config"
    }
}
$(BBDown_config)
# $(cmd_tool_auto_check_down "N_m3u8DL-RE" "https://github.moeyy.xyz/https://github.com/nilaoda/N_m3u8DL-RE/releases/download/v0.2.0-beta/N_m3u8DL-RE_Beta_win-x64_20230628.zip" "$HOME\Downloads" "C:\Tools\bin")
# $(cmd_tool_auto_check_down "N_m3u8DL-RE" "https://github.moeyy.xyz/https://github.com/nilaoda/N_m3u8DL-RE/releases/download/v0.2.1-beta/N_m3u8DL-RE_Beta_win-x64_20240828.zip" "$HOME\Downloads" "C:\Tools\bin" "N_m3u8DL-RE_Beta_win-x64")
$(cmd_tool_auto_check_down "N_m3u8DL-RE" "https://github.moeyy.xyz/https://github.com/nilaoda/N_m3u8DL-RE/releases/download/v0.3.0-beta/N_m3u8DL-RE_v0.3.0-beta_win-x64_20241203.zip" "$HOME\Downloads" "C:\Tools\bin" "N_m3u8DL-RE_Beta_win-x64")
$(cmd_tool_auto_check_down "lazygit" "https://github.moeyy.xyz/https://github.com/jesseduffield/lazygit/releases/download/v0.42.0/lazygit_0.42.0_Windows_x86_64.zip" "$HOME\Downloads" "C:\Tools\bin")


# [UnZip for Windows](https://gnuwin32.sourceforge.net/packages/unzip.htm)
# [windows10 下 zip命令行参数详解_windows自带zip命令行-CSDN博客](https://blog.csdn.net/MAO_SHUO/article/details/104360423)

# [在powershell中，如果文件还不存在，如何在一定时间后重试下载？-腾讯云开发者社区-腾讯云](https://cloud.tencent.com/developer/ask/sof/106515823/answer/114906947)
# [使用 PowerShell 压缩和解压缩文件 | D栈 - Delft Stack](https://www.delftstack.com/zh/howto/powershell/compress-and-unzip-files-using-powershell/)
# [Takeown、Cacls、Icacls-文件、文件夹夺权用法_将目录下所有文件、文件夹、子文件夹、子文件的所有者设置为管理原组-CSDN博客](https://blog.csdn.net/wenzhongxiang/article/details/88143281)
# [使用PowerShell管理文件访问权限 - 简书](https://www.jianshu.com/p/262b0d93d0a7)
# [System.UnauthorizedAccessException: 对路径“.......”的访问被拒绝的解决办法-CSDN博客](https://blog.csdn.net/Ly_LittleStar/article/details/123378456)
#------------------------------- Auto Download END ----------------------------------

#------------------------------- Import Env BEGIN -----------------------------------

# --- Anaconda配置 ------------------------------------------------------------- 
# 使用`conda init`会在C:\Users\Auroa\Documents\WindowsPowerShell下创建profile.ps1并在里面添加以下
#region conda initialize
# !! Contents within this block are managed by 'conda init' !!
#If (Test-Path "C:\ProgramData\anaconda3\Scripts\conda.exe") {
#    (& "C:\ProgramData\anaconda3\Scripts\conda.exe" "shell.powershell" "hook") | Out-String | ?{$_} | Invoke-Expression
#}
#endregion

$anaconda_insatll_path = "C:\ProgramData\anaconda3\Scripts\conda.exe"


#------------------------------- Import Env END -------------------------------------

#------------------------------- Import Modules BEGIN -------------------------------
# 引入 posh-git
Import-Module posh-git

# 引入 oh-my-posh
# Import-Module oh-my-posh

# 引入 ps-read-line
Import-Module PSReadLine

# 设置 PowerShell 主题
# Set-PoshPrompt ys
# Set-PoshPrompt paradox
## 安装字体
#scoop bucket add nerd-fonts
#scoop install SarasaGothic-SC           # 安装更纱黑体（简体中文）
#scoop install Wenquanyi-Microhei    # 安装文泉驿微米黑
#scoop install Wenquanyi-Zenhei       # 安装文泉驿正黑
# 或者去下载 https://www.nerdfonts.com/font-downloads
# 解压后 点击 选择位所以用户安装 打开设置
# 对于Windows Terminal修改settings.json中的"fontFace"项为Nerd字体即可，注意要更改为其显示的正式名称；
# windows powershell --》字体–》调整字号，最后保存即可

#------------------------------- Import Modules END   -------------------------------

#------------------------------- Modules Config BEGIN -------------------------------
# --- posh-git 模块配置 ------------------------------------------------------------- 
## 安装 Install-Module posh-git -Scope CurrentUser
## 导入模块posh-git
Import-Module posh-git
## 配置
if ($OsVersion -eq 7) {
    # [Console]::OutputEncoding = [System.Text.Encoding]::UTF8 # 需启用 ANSI 支持
    ## - 设置目录地址使用~替代
    $GitPromptSettings.DefaultPromptAbbreviateHomeDirectory = $true
    #$GitPromptSettings.DefaultPromptWriteStatusFirst = $true

    #$GitPromptSettings.DefaultPromptBeforeSuffix.Text = '`n$([DateTime]::now.ToString("MM-dd HH:mm:ss"))'
    $GitPromptSettings.DefaultPromptSuffix = ' $((Get-History -Count 1).id + 1)$(" > " * ($nestedPromptLevel + 1)) '

    $GitPromptSettings.BeforePath = '['
    $GitPromptSettings.AfterPath = ']'
    $GitPromptSettings.BeforePath.ForegroundColor = 'Green'
    $GitPromptSettings.AfterPath.ForegroundColor = 'Green'
    $GitPromptSettings.DefaultPromptPath.ForegroundColor = 'Red'
    #$GitPromptSettings.DefaultPromptPath.ForegroundColor = 0xFFA500

    ## - 颜色设置
    If (Test-Path $anaconda_insatll_path) {
        # (& "$anaconda_insatll_path" "shell.powershell" "hook") | Out-String | ?{$_} | Invoke-Expression
        $anaconda_env_name =  (& "$anaconda_insatll_path" "shell.powershell" "hook") | Out-String | ?{$_} | Invoke-Expression
        $GitPromptSettings.DefaultPromptPrefix.Text = '$env:USERNAME $(Get-Date -f "MM-dd HH:mm:ss")'
        $GitPromptSettings.DefaultPromptPrefix.ForegroundColor = [ConsoleColor]::Magenta
    } else {
        # $GitPromptSettings.DefaultPromptPrefix.Text = '[Python $(pyenv version-name)] $(Get-Date -f "MM-dd HH:mm:ss") '
        $GitPromptSettings.DefaultPromptPrefix.Text = '$env:USERNAME $(Get-Date -f "MM-dd HH:mm:ss") '
        $GitPromptSettings.DefaultPromptPrefix.ForegroundColor = [ConsoleColor]::Magenta
        #$GitPromptSettings.DefaultPromptBeforeSuffix.ForegroundColor = 0x808080
        #$GitPromptSettings.DefaultPromptBeforeSuffix.ForegroundColor = 'Orange'
    }

    ## - 换行
    # 使用-not运算符判断
    if ( -not $(which "pyenv")) { 
        $GitPromptSettings.DefaultPromptBeforeSuffix.Text = '`n' 
    } else {
        $GitPromptSettings.AnsiConsole = $true
        # $GitPromptSettings.DefaultPromptPrefix.ForegroundColor = $null # 关闭默认颜色
        $GitPromptSettings.DefaultPromptPrefix.Text = '($(pyenv version-name)) $env:USERNAME '
        # $GitPromptSettings.DefaultPromptBeforeSuffix.Text = '[Python $(pyenv version-name)]`n'
        $GitPromptSettings.DefaultPromptBeforeSuffix.Text = ' $(Get-Date -f "MM-dd HH:mm:ss")`n'
        $GitPromptSettings.DefaultPromptBeforeSuffix.ForegroundColor = 'Orange' 
        
    }
} else {
    ## V2
    # 使用-not运算符判断
    function diyprompt { 

        # 
        if ( -not $(which "pyenv")) { 
            Write-Host "$env:USERNAME " -NoNewline -ForegroundColor Blue # 用户名（蓝色）
            Write-Host "$(Get-Date -f 'MM-dd HH:mm:ss') " -NoNewline -ForegroundColor Magenta # 时间（洋红色）
        } else {
            Write-Host "($(pyenv version-name)) " -NoNewline -ForegroundColor Magenta # python 版本
            Write-Host "$env:USERNAME " -NoNewline -ForegroundColor Blue # 用户名（蓝色）
            Write-Host "$(Get-Date -f 'MM-dd HH:mm:ss') " -NoNewline -ForegroundColor Magenta # 时间（洋红色）
        }
    }
    # 调用 posh-git 的默认逻辑（显示路径和 Git 状态）
    $GitPromptSettings.DefaultPromptBeforeSuffix.Text = '$(diyprompt) `n' 
    $GitPromptSettings.DefaultPromptAbbreviateHomeDirectory = $true # - 设置目录地址使用~替代
    $GitPromptSettings.DefaultPromptSuffix = ' $((Get-History -Count 1).id + 1)$(" PS> " * ($nestedPromptLevel + 1)) '
    $GitPromptSettings.BeforePath = '['
    $GitPromptSettings.AfterPath = ']'
    $GitPromptSettings.BeforePath.ForegroundColor = 'Green'
    $GitPromptSettings.AfterPath.ForegroundColor = 'Green'
    $GitPromptSettings.DefaultPromptPath.ForegroundColor = 'Orange'
    # $GitPromptSettings.DefaultPromptPrefix.Text = "$(diyprompt)"
    If (Test-Path $anaconda_insatll_path) {
        # (& "$anaconda_insatll_path" "shell.powershell" "hook") | Out-String | ?{$_} | Invoke-Expression
        $anaconda_env_name =  (& "$anaconda_insatll_path" "shell.powershell" "hook") | Out-String | ?{$_} | Invoke-Expression
        $GitPromptSettings.DefaultPromptPrefix.Text = '$env:USERNAME $(Get-Date -f "MM-dd HH:mm:ss")'
        $GitPromptSettings.DefaultPromptPrefix.ForegroundColor = [ConsoleColor]::Magenta
    }
}
# --- PSReadLine 模块配置 ---------------------------------------------------------------- 
#Get-PSReadLineOption         # 显示所有可以配置的选项
#Get-PSReadLineKeyHandler     # 显示所有可以配置的快捷键
Set-PSReadlineKeyHandler -Key Tab -Function Complete            # Tab自动补全
Set-PSReadlineKeyHandler -Key Tab -Function MenuComplete
#Set-PSReadLineKeyHandler -Key "Ctrl+d" -Function MenuComplete
Set-PSReadLineKeyHandler -Key "Ctrl+z" -Function Undo
Set-PSReadLineKeyHandler -Key UpArrow -Function HistorySearchBackward
Set-PSReadLineKeyHandler -Key DownArrow -Function HistorySearchForward

# 安装： Install-Module -Name PSReadLine -AllowClobber -Force
# Import-Module PSReadLine
# 启用预测 IntelliSense 
#（预测性 IntelliSense 是对 Tab 键补全概念的补充，可帮助用户成功补全命令。 它使用户能够基于用户的历史记录和其他特定于域的插件中的匹配预测来发现、编辑和执行完整命令。）
#Set-PSReadLineOption -PredictionSource History
# 自定义键绑定
Set-PSReadLineKeyHandler -Key UpArrow -Function HistorySearchBackward

# --- PSFzf 模块配置 ---------------------------------------------------------------- 
# [GitHub - kelleyma49/PSFzf: A PowerShell wrapper around the fuzzy finder fzf](https://github.com/kelleyma49/PSFzf)
## 安装 Install-Module PSFzf -Scope CurrentUser
## 安装旧版本：Install-Module -Name PSFzf -RequiredVersion 2.0.0
## 导入 PSFzf
# Import-Module PSFzf
# 设置变量值
if ($OsVersion -eq 7) {
    # win7 不支持--height特性
    $env:FZF_DEFAULT_OPTS ="--layout=reverse --inline-info"
} else {
    $env:FZF_DEFAULT_OPTS ="--height=50% --layout=reverse --inline-info"
}
# 初始时打开历史目录选择
#Set-Location (Get-ChildItem . -Recurse | ? { $_.PSIsContainer } | Invoke-Fzf)
# 启用选项卡扩展支持
# Set-PSFzfOption -TabExpansion

## 使用fzf作为Tab补全菜单
#Set-PSReadLineKeyHandler -Key Tab -ScriptBlock { Invoke-FzfTabCompletion }
Set-PSReadLineKeyHandler -Key "Ctrl+d" -ScriptBlock { Invoke-FzfTabCompletion }

# example command - use $Location with a different command:
#$commandOverride = [ScriptBlock]{ param($Location) Write-Host $Location }
# pass your override to PSFzf:
#Set-PsFzfOption -AltCCommand $commandOverride

## 用您喜欢的绑定替换 'Ctrl+t' 和 'Ctrl+r'：Ctrl+r默认通过 PSReadline 历史反向搜索
## 设置 PsFzf 的历史记录和文件查找器键盘快捷键
#Set-PSFzfOption -PSReadlineChordProvider 'Ctrl+t' -PSReadlineChordReverseHistory 'Ctrl+r'


# --- z.lua 模块配置 ---------------------------------------------------------------- 
# 安装z.lua : scoop install z.lua (如果中间安装失败，去 用户目录下的 C:\Users\用户名\scoop/app/z.lua)
# Invoke-Expression (& { (lua C:\Users\whoami\scoop\apps\z.lua\current\z.lua --init powershell) -join "`n" })
# Invoke-Expression (& { (lua  .\scoop\apps\z.lua\current\z.lua --init powershell) -join "`n" })
# Invoke-Expression (& { (lua  C:\Users\iamx\scoop\apps\z.lua\current\z.lua --init powershell) -join "`n" })
# Invoke-Expression (& { (lua  $home\scoop\apps\z.lua\current\z.lua --init powershell) -join "`n" })
# Invoke-Expression (& { (lua  C:\Users\VvV\scoop\apps\z.lua\current\z.lua --init powershell) -join "`n" })
# Invoke-Expression (& { (lua  C:\Users\ThinkPad\scoop\apps\z.lua\current\z.lua --init powershell) -join "`n" })
# Invoke-Expression (& { (lua C:\Tools\z.lua-1.8.13\z.lua --init powershell) -join "`n" })
Invoke-Expression (& { (lua C:\Tools\z.lua\z.lua --init powershell) -join "`n" })

# z.lua 快捷用法
# 回到历史路径，用 fzf 进行历史路径操作
function  zh {
    z -I -t .
}
# 使用交互式选择模式
function  zi {
    z -i
}
# 使用 fzf 对多个结果进行选择
function  zl {
    z -l
}
# 快速回到父目录
function  zb {
    z -b
}

function  vimf {
    #vim $(fzf --height=60% --preview 'ls -alh {}')
    Get-ChildItem . -Recurse -Attributes !Directory | Invoke-Fzf | % { vim $_ }
}

function  nvimf {
    # nvim $(fzf --height=60% --preview 'ls -alh {}')
    Get-ChildItem . -Recurse -Attributes !Directory | Invoke-Fzf | % { nvim $_ }
}

# 使用cd fd fzf 查找与切换目录
function  cdf {
  # cd $(fd -t d  | fzf )
  # 管道传入fzf出现中文乱码
  # 取巧办法 控制面板-> 区域 -> 设置UTF-8
  #fdfzf | cd
  # 需要建立一个fdfzf.bat脚本 内容为 fd -t d | fzf 并将其加入系统环境变量中
   
  # PSFzf下
   Get-ChildItem . -Recurse -Attributes Directory | Invoke-Fzf | Set-Location
}


#------------------------------- Modules Config END ---------------------------------

#-------------------------------  Set Hot-keys BEGIN  -------------------------------
#禁用默认按键：
Remove-PSReadlineKeyHandler 'Ctrl+r' 

# 设置预测文本来源为历史记录
#Set-PSReadLineOption -PredictionSource History

# 每次回溯输入历史，光标定位于输入内容末尾
Set-PSReadLineOption -HistorySearchCursorMovesToEnd

# 设置 Tab 为菜单补全和 Intellisense
Set-PSReadLineKeyHandler -Key "Tab" -Function MenuComplete

# 设置 Ctrl+d 为退出 PowerShell
#Set-PSReadlineKeyHandler -Key "Ctrl+d" -Function ViExit

# 设置 Ctrl+z 为撤销
#Set-PSReadLineKeyHandler -Key "Ctrl+z" -Function Undo

# 设置向上键为后向搜索历史记录
#Set-PSReadLineKeyHandler -Key UpArrow -Function HistorySearchBackward

# 设置向下键为前向搜索历史纪录
#Set-PSReadLineKeyHandler -Key DownArrow -Function HistorySearchForward
#-------------------------------  Set Hot-keys END    -------------------------------





#-------------------------------    Functions BEGIN   -------------------------------
# Python 直接执行
$env:PATHEXT += ";.py"

# 更新系统组件
function Update-Packages {
	# update pip
	Write-Host "Step 1: 更新 pip" -ForegroundColor Magenta -BackgroundColor Cyan
	$a = pip list --outdated
	$num_package = $a.Length - 2
	for ($i = 0; $i -lt $num_package; $i++) {
		$tmp = ($a[2 + $i].Split(" "))[0]
		pip install -U $tmp
	}

	# update TeX Live
	$CurrentYear = Get-Date -Format yyyy
	Write-Host "Step 2: 更新 TeX Live" $CurrentYear -ForegroundColor Magenta -BackgroundColor Cyan
	tlmgr update --self
	tlmgr update --all

	# update Chocolotey
	Write-Host "Step 3: 更新 Chocolatey" -ForegroundColor Magenta -BackgroundColor Cyan
	choco outdated
}


function touch($name){
  if ($name) {
    $file_path = Split-Path -Path $name
    $file_name = Split-Path -Path $name -Leaf
    if ($file_path -eq "") {
      $file_path = "."
    }
    if (-Not (Test-Path($file_path))) {
      New-Item -ItemType "directory" -Path $file_path
    }
    New-Item -Path $file_path -Name $file_name -ItemType "file"
  }
  else {
     Write-Host "Command to create new file."
  }
}

# [Releases · nilaoda/N_m3u8DL-RE · GitHub](https://github.com/nilaoda/N_m3u8DL-RE/releases)
# m3u8 下载
function  m3u8dl($videoname , $m3u8url){
    # echo  "this is a test m3u8dl" 
    # echo $videoname
    # echo $m3u8url
    $dow_video_path="$HOME/Downloads/$videoname.mp4"
    echo "[Debug] dow_video_path = $dow_video_path"
    $flagStatus=(Test-Path $dow_video_path)
    echo "[Debug] flagStatus = $flagStatus"
    if ( $flagStatus ) {
        echo "[INFO] $dow_video_path  exist."
        # remove-Item -Recurse -Force $dow_video_path
    } else {
        # echo "F"
        # echo "[Debug]  $dow_video_path does not exist."

        # 方法1：使用Get-Processc获取命令进程
        ## - [powershell与进程相关的操作（get-process）-CSDN博客](https://blog.csdn.net/purvispanwu/article/details/114760807)
        ## - [如何在PowerShell或C＃中获取进程的命令行信息 | 码农家园](https://www.codenong.com/17563411/)
        # 命令例子： Get-Process -name *N_m3u8DL-RE*
        # $processNameString="*$videoname*"
        # echo "[Debug] processNameString = $processNameString"
        # $flagProcessID=(Get-Process -name $processNameString | Select-Object id | ForEach-Object -Process{$_.id} )
        # echo "[Debug] flagProcessID = $flagProcessID"
        # 注：Get-Process 查找的到得只能是名字，无法区分同名下不同输入参数

        # 方法2：使用wmic获取命令进程命令行参数
        ## - [[Windows]wmic查看运行进程的参数 - XueXueLai - 博客园](https://www.cnblogs.com/DiZhang/p/12544793.html)
        ## - [cmd方式获取进程启动命令行commandline_cmd命令打开进程-CSDN博客](https://blog.csdn.net/baidu_38621657/article/details/113788299)
        ## - [[Windows]wmic查看运行进程的参数_wmic process where name-CSDN博客](https://blog.csdn.net/ShelleyLittlehero/article/details/89920329)
        ## - [Windows wmic命令之process进程管理_wmic process-CSDN博客](https://blog.csdn.net/yetugeng/article/details/103615205)
        # 命令例子： wmic process get caption,commandline /value | findstr "Notepad.exe" |  findstr "新建文件.txt"
        $cmdString="N_m3u8DL-RE --tmp-dir=$HOME/Downloads --save-dir=$HOME/Downloads --save-name=$videoname $m3u8url"
        echo "[INFO]  cmdString = $cmdString" 
        $flagProcessFlag=(wmic process get caption,commandline /value | findstr "N_m3u8DL-RE" | findstr "$m3u8url")
        echo "[Debug]  flagProcessFlag = $flagProcessFlag" 
        #if ( $flagProcessID ) { # 输入参数是空
        #    echo "[INFO]  The process of $cmdString Process exist (id = $flagProcessID)."
        If([String]::IsNullOrEmpty($flagProcessFlag)){ # 输入参数是空
            Write-Host "[INFO] The process of $cmdString  does not exist." 
            # [Executing a command stored in a variable from PowerShell - Stack Overflow](https://stackoverflow.com/questions/3592851/executing-a-command-stored-in-a-variable-from-powershell)
            Invoke-Expression $cmdString # 执行命令
        } else {
            echo "[INFO]  The process of $cmdString  exist. "
        }

        # If([String]::IsNullOrEmpty($TargetPath)){ # 输入参数是空
        #    Write-Host "[INFO] The string is null or empty."
        #    $TargetPath="./"
        # }
        # else {
        #    Write-Host "[INFO] The string is not empty."
        # }
    }
}


# 
function read-txt-ffmpeg-merge($txt_file_path){
    $m3u8_video_name =( $txt_file_path -split  '\\' )[-1]
    #echo "[Debug] m3u8_video_name = $m3u8_video_name"
    $m3u8_video_name =( $txt_file_path -split  '-file.txt' )[0]
    #echo "[Debug] m3u8_video_name = $m3u8_video_name"
    $save_mp4_path = "$m3u8_video_name.mp4"
    #echo "[Debug] save_mp4_path = $save_mp4_path"

    # $ps_version = (Get-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\PowerShell\3\PowerShellEngine -Name 'PowerShellVersion').PowerShellVersion
    # echo "[Debug] PowerShell Version = $ps_version"
    # 如果PowerShell版本号是5则进行文本格式转换为 Utf8 No Bom
    # 注意 终端powershell是GBK编码，所以打印出来的中文是乱码。
    # [将powershell的编码默认改为UTF-8_powershell编码改为utf8-CSDN博客](https://blog.csdn.net/qq_39494169/article/details/122561317)
    # [shell - 如何解决 ffmpeg concat 命令错误 "unknown keyword..."？ - IT工具网](https://www.coder.work/article/7751036)
    # [修改Windows PowerShell中重定向输出到文件时的文本编码_powershell 输出编码-CSDN博客](https://blog.csdn.net/yakamoz423/article/details/134696323)

    $txt_file_path_Utf8NoBom = "$m3u8_video_name-file-Utf8NoBom.txt"
    #(Get-Content $txt_file_path) | Out-FileUtf8NoBom $txt_file_path

    (Get-Content $txt_file_path) | Out-FileUtf8NoBom $txt_file_path_Utf8NoBom

    # 开始合并
    $cmdStr = "ffmpeg -f concat -safe 0  -i $txt_file_path_Utf8NoBom -c copy $save_mp4_path"
    echo "[INFO] $cmdStr"
    # 执行合并命令
    # ffmpeg -f concat -safe 0  -i $txt_file_path -c copy $save_mp4_path
    Invoke-Expression $cmdStr 
    # iex $cmdStr 
    # [Executing a command stored in a variable from PowerShell - Stack Overflow](https://stackoverflow.com/questions/3592851/executing-a-command-stored-in-a-variable-from-powershell)

    #  删除多余的中间文件
    del  $txt_file_path
    del  $txt_file_path_Utf8NoBom
    # [powershell 删除一个文件或文件夹_powershell exclude-CSDN博客](https://blog.csdn.net/lixiaohuiok111/article/details/78427568)
}

# 合并ts文件成视频
function ffmpeg-merge-ts($ts_folder_root_path) {
    $ts_folder_root_path =$ts_folder_root_path.Trimend("\") # 去除尾部\
    #echo "[Debug] ts_folder_root_path = $ts_folder_root_path"
    # -split '\s+'-它被一个或多个空格分割。
    # (...)[1]然后，使用索引[1]返回第二项（因为数组索引是zero-based)）。
    $m3u8_video_name =( $ts_folder_root_path -split  '\\' )[-1]
    #echo "[Debug] m3u8_video_name = $m3u8_video_name"
    # 切换到路径的上一层
    cd $ts_folder_root_path
    cd ..
    $save_txt_path = "./$m3u8_video_name-file.txt"

    #echo "" > $save_txt_path # 创建一个只有一空行的文本文件行
    # echo "" | Out-File $save_txt_path # 创建一个只有一空行的文本文件行 
    echo "" | Out-File   $save_txt_path 
    # PowerShell 5.0的版本，进行$PSDefaultParameterValues['Out-File:Encoding'] = 'utf8'这样设置后，使用>或>>重定向是不行的，必须通过Out-File命令进行重定向才会生效。

    Clear-Content $save_txt_path  # 空清空文本文件
    # 扫描路径
    Get-ChildItem ./$m3u8_video_name | ?{$_.psiscontainer -eq $true} | ForEach-Object -Process {
        # echo $_ 
        # 找到目录文件夹切换 
        $ts_sub_path = $_.name
        #echo "[Debug] ts_sub_path = $ts_sub_path"
        # Get-ChildItem ./ -Include *.ts -recurse > ../file.txt
        # 在Get-ChildItem这个cmdlet中，-Recurse表示是否循环遍历子目录，而-Include表示筛选条件。
        
        #echo "[Debug] save_txt_path = $save_txt_path"
        $ts_path = "./$m3u8_video_name/$ts_sub_path"
        #echo "[Debug] ts_path = $ts_path"
        Get-ChildItem $ts_path -Include *.ts -recurse | ForEach-Object -Process {
            # echo $_ 
            $ts_file_path = $_.name
            #echo "[Debug] ts_file_path = $ts_file_path"
            $ts_file_full_path = "$ts_path/$ts_file_path"
            #echo "[Debug] ts_file_full_path = $ts_file_full_path"
            # echo "file '$ts_file_full_path'" >> $save_txt_path
            # echo "file '$ts_file_full_path'" | Out-File -Append $save_txt_path
            echo "file '$ts_file_full_path'" | Out-File  -Append $save_txt_path
            # PowerShell 5.0的版本，进行$PSDefaultParameterValues['Out-File:Encoding'] = 'utf8'这样设置后，使用>或>>重定向是不行的，必须通过Out-File命令进行重定向才会生效
            # if($_ -is [System.IO.FileInfo])
            # {
            #     # Write-Host($_.name);    
            # }
        }
    }


    # 读取生成的*-file.txt 合并视频
    read-txt-ffmpeg-merge $save_txt_path
}

# 批量合并文件夹下的m3u8的下载视频ts
function  multiple-ffmpeg-merge-ts($folder_path) {
  # 切换路径
  cd  $folder_path
  # 查看当前目录下所有的mp4后缀的文件
  Get-ChildItem ./ -Include *.mp4 -recurse > ./1.txt
  # 遍历
  For($i=0;$i -lt $_.Count; $i++) {
    Write-Host "parameter $i : $($_[$i])"
  }

  # 读取生成的*-file.txt 合并视频
}

function fast-ffmpeg-merge($findPath){
  # 切换路径
  cd  $findPath
  # Get-ChildItem . -Include *.mp4 -recurse > ./1.txt
  # -Recurse * 用于从指定路径开始递归地获取所有文件和文件夹。通过使用通配符*，可以获取路径下的所有项。
  # where{!$_.PSIsContainer} ，用于找出不是文件夹的文件。它将返回在当前路径下所有不是文件夹的文件。
  #$fileList = Get-ChildItem $findPath -Include *.mp4  -Recurse
  $fileList = Get-ChildItem  -Include *.mp4  -Recurse
  echo "[Debug] fileList = $fileList ";
  # $PSDefaultParameterValues['Out-File:Encoding'] = 'utf8'
  # 遍历
  foreach($file in $fileList) {
    $fileName = $file.name
    echo "[Debug] fileName = $fileName";
    # -split '\s+'-它被一个或多个空格分割。
    # (...)[1]然后，使用索引[1]返回第二项（因为数组索引是zero-based)）。
    $newFileName =( $fileName -split  '[0-9]+.mp4' )[0]
    echo "[Debug] newFileName= $newFileName";
    $saveFilePath="$newFileName"+"-file.txt"
    #echo "[Debug] saveFilePath= $saveFilePath";
    echo "" > $saveFilePath ;
    # echo ""  | Out-File  $saveFilePath ;
    # echo ""  | Out-File  $saveFilePath -encoding utf8;
    # 先清空文件确保不会有已存在的内容
    Clear-Content  $saveFilePath  # 删除文件中的所有内容。 不删除这些文件，但它们为空。
    # 遍历
    foreach($file1 in $fileList) {
      # -match 'rdp'-首先与rdp匹配，一旦获得匹配，
      $flagStatus = $file1 -match $newFileName
      #echo "[Debug] flagStatus = $flagStatus ";
      if ( $flagStatus ) {
        #echo "T"
        echo "file  '$file1'" >> $saveFilePath
        # echo "file  '$file1'"  | Out-File -Append $saveFilePath ;
        # echo "file  '$file1'"  | Out-File -Append $saveFilePath -encoding utf8;
      } else {
        # echo "F"
      }
    }
  }

  
    #   # 读取生成的*-file.txt 合并视频
    #   $txtFileList = Get-ChildItem  -Include *.txt  -Recurse
    #   foreach($txtFile in $txtFileList ) {
    #     # -match 'rdp'-首先与rdp匹配，一旦获得匹配，
    #     $flagStatus = $txtFile -match '-file.txt'
    #     echo "[Debug] flagStatus = $flagStatus ";
    #     if ( $flagStatus ) {
    #       # echo "T"
    #       $prjName =( $txtFile.name -split  '-file.txt' )[0]
    #       echo "prjName  = $prjName "
    #       # 执行开始合并命令
    #       # ffmpeg   -allowed_extensions ALL -protocol_whitelist -f concat -safe 0  -i $txtFile  -c copy   -vcodec lib264 "$prjName"+".mp4"
    #       # ffmpeg  -f concat  -i  "$txtFile"  -c copy   "$prjName"+".mp4"
    #       ffmpeg  -f concat -safe 0 -i  "$txtFile"  -c copy   "$prjName"+".mp4"
        
    #       # 使用ffmpeg进行多个视频合并过程中出现了“unsafe file name”错误，解决的办法是加个-safe 0 参数
    #       # 删除 txt文件
    #       # Remove-Item $txtFile   -recurse  # -recurse 参数绕过确认提示
    #     } else {
    #       echo "F"
    #     }
    #   }
    # 读取生成的*-file.txt 合并视频
    read-txt-ffmpeg-merge $saveFilePath
}

# 关于ffmpeg Invalid data found when processing input错误
# ffmpeg库不支持，例如ffmpeg -i 1.mkv -vcodec lib264 2.mp4，你想转码成264进行输出，如果你的ffmpeg在编译时没有x264库，那么会报非法数据，因为ffmpeg编码264时，依赖x264进行编码。其它情况类似，排查这种问题可以根据这个输入文件或者输入流的音视频编码类型，然后再看ffmpeg支持的编解码器类型是否支持你想要输出的类型。
# 然后再配合ffmpeg的源码去判断，例如在ffmpeg源码中搜索"ffmpeg Invalid data found when processing input"这些关键错误信息。

function ffmpeg-ts2mp4($TargetPath){
    $findFile = $TargetPath
    $findFileName = $findFile.name
    Write-Host "[Debug] findFileName = $findFileName."
    # $findFileNameNo =( $findFileName -split  '\\' )[-1] # 根据分割符\切分
    $fileExtension = [System.IO.Path]::GetExtension($findFileName);
    echo "[Debug] fileExtension = $fileExtension "
    switch($fileExtension) 
    {
      ".ts" {
            echo  "[Debug] this is a .ts file"
            $findFileFullName = $findFile.FullName
            echo  "[Debug] findFileFullName = $findFileFullName"
            $newFileName = $( $findFileFullName -split  '\.' )[0]+".mp4"
            echo "[Debug] newfilename = $newFileName";
            # 执行命令
            # ts 转换 mp4
            echo "[INFO] cmd: ffmpeg -i $findFileFullName  -acodec copy -vcodec copy  -f mp4  $newFileName";
            ffmpeg -i   $findFileFullName  -acodec copy -vcodec copy  -f mp4  $newFileName
        }
        default {
            echo  "[INFO] this is not a .ts file" 
        }
    }
}

# ffmpeg将ts文件转换为mp4
function ts2mp4($TargetPath){
    $TargetPath =$TargetPath.Trimend("\") # 去除尾部\
    echo "[Debug] TargetPath=$TargetPath";
    If([String]::IsNullOrEmpty($TargetPath)){ # 输入参数是空
       Write-Host "[INFO] The string is null or empty."
       $TargetPath="./"
    }
    else {
       Write-Host "[INFO] The string is not empty."
    }
    echo "[Debug] TargetPath=$TargetPath";
    if (Test-Path $TargetPath){ # 判断输入路径是否存在有效,是返回True
        Write-Host "[Debug] $TargetPath is exist."
        # 判断输入路径是文件还是文件夹路径
        # Write-Host "[Debug] $(Test-Path -Path $TargetPath -PathType Container)"  # 判断输入路径是否是文件夹路径，是返回True
        if (Test-Path -Path $TargetPath -PathType Container){ # 判断输入路径是否是文件夹路径，是返回True
            Write-Host "[Debug] $TargetPath is folder."
            # 遍历目录下ts文件批量转换
            $findFileList = Get-ChildItem $TargetPath -Include *.ts -Recurse           # 遍历获取目录下的ts文件列表
            # $findFileList = Get-ChildItem $TargetPath  -Include *.ts  -Recurse # 递归遍历获取目录下的ts文件列表
            Write-Host "[Debug] findFileList = $findFileList."
            foreach($findFile in $findFileList) {
                ffmpeg-ts2mp4 $findFile
            }
        } else {
            Write-Host "[INFO] $TargetPath is file."
            ffmpeg-ts2mp4 $findFile
        }
    } else {
        Write-Host "[INFO] $TargetPath is not exist."
    }
}

# 压缩包密码破解
function compressed-cracking($compressedFilePath){
  echo $compressedFilePath
  # $fileName=$compressedFilePath.Name;
  # $fileName = [System.IO.Path]::GetFileNameWithoutExtension($compressedFilePath)
  # echo $fileName;
  # $fileSize = "$($compressedFilePath.Length) bytes";
  #echo $fileSize;
  # $fileExtension = (Split-Path -Path $compressedFilePath -Leaf).Split(".") ;
  $fileExtension = [System.IO.Path]::GetExtension($compressedFilePath);
  echo $fileExtension;
  switch($fileExtension) 
  {
      ".zip" {
      echo  "this is a .zip file" 
    }
        ".7z" {
      echo  "this is a .7z file" 
    }
    default { 
      echo  "this is a unknow file" 
    } 
  }
}


## amr2mp3
function amr2mp3($FilePath){
  echo "[INFO] amr_path=$FilePath";
  $fileName = [System.IO.Path]::GetFileNameWithoutExtension($FilePath);
  echo "[INFO] fileName=$fileName";
  $fileExtension = [System.IO.Path]::GetExtension($FilePath);
  echo "[INFO] fileExtension = $fileExtension ";
  switch($fileExtension) 
  {
      ".amr" {
            echo  "[INFO] this is a .amr file" 
            $newFileName = $fileName+".mp3"
            echo "[INFO] newfilename = $newFileName";
            # 执行命令
            ffmpeg -i $FilePath $newFileName
        }
        default {
            echo  "[INFO] this is not a .amr file" 
            # $newFileName = $fileName+".mp3"
            # echo "[INFO] newfilename = $newFileName";
        }
  }
}

## 删除 ._*文件 、.~*文件、~*文件、.DS_Store 文件
## [windows - Windows10: how do delete .DS_STORE files via powershell/command prompt? - Super User](https://superuser.com/questions/1220151/windows10-how-do-delete-ds-store-files-via-powershell-command-prompt)
function clearDS_Store($TargetPath){
    If([String]::IsNullOrEmpty($TargetPath)){
       Write-Host "[INFO] The string is null or empty."
       $TargetPath="./"
    }
    else {
       Write-Host "[INFO] The string is not empty."
       cd $TargetPath
    }
    echo "[INFO] TargetPath=$TargetPath";
    
    # 删除
    #del /s .DS_store

    # 删除
    # Get-ChildItem * -Include .DS_store -Recurse | Remove-Item

    # 输出 $TargetPath 下所有文件的文件名
    # Get-ChildItem $TargetPath | ForEach-Object -Process{
    #     if($_ -is [System.IO.FileInfo])
    #     {
    #         Write-Host($_.name);
    #     }
    # }
    # 遍历递归输出 $TargetPath 下所有文件的文件名
    Get-ChildItem $TargetPath -Recurse -ErrorAction SilentlyContinue  -Force | ForEach-Object -Process{
        # echo "[INFO]  $($_.FullName)"
        if($_ -is [System.IO.FileInfo])
        { # 是文件时的判断
            # echo ($_.name -match '^\._*')
            #echo ($_.name -match '^\~')
            # $_.name"; # 获取文件名 $_.FullName"; # 获取文件的完整路径
            if  ( (($_.name) -match '^\.DS_Store') ){
                echo "[INFO]  $($_.FullName) is .DS_Store file.  ";
                Remove-Item -Force $_.FullName # 删除
            }
            elseIf ( (($_.name) -match '^\._') ){
                echo "[INFO]  $($_.FullName) is ._* file.";
                Remove-Item -Force $_.FullName # 删除
            }
            elseIf ( (($_.name) -match '\.swap$') ){
                echo "[INFO]  $($_.FullName) is *.swap file. ";
                Remove-Item -Force $_.FullName # 删除
            }
            elseIf  ( (($_.name) -match '^\~') ){ # 此处有问题
                echo "[INFO]  $($_.FullName) is ~* file.";
                Remove-Item -Force $_.FullName # 删除
            } 
            # else{
            #     echo "[INFO] $($_.FullName) is not find file.";
            # }
        }
    }

    # Get-ChildItem -Path $env:windir -Recurse -ErrorAction SilentlyContinue |
    #     Where-Object { $_.BaseName -match '^\d{2}' }

    # 找出 $TargetPath 目录下的所有文件
    # Get-ChildItem $TargetPath | ?{$_.psiscontainer -eq $false}
 
    # [PowerShell遍历文件、文件夹的方法_遍历 powershell-CSDN博客](https://blog.csdn.net/saga_gallon/article/details/51943724)
    #[PowerShell笔记 - 13.正则表达式 - 门前有根大呲花 - 博客园](https://www.cnblogs.com/MerLin-LiuNian/p/15308860.html)
}

function InitSettingGitConfig {
    # git
    git config --global core.quotepath false  
    git config --global gui.encoding utf-8  
    git config --global i18n.commit.encoding utf-8  
    git config --global i18n.logoutputencoding utf-8 
    # ssh 
}

function tig() {
    
    $arguments=""
    foreach($element in $args) {
        $arguments += " $element"
    }    

    if(-Not ($env:PATH.Contains("C:\cygwin64\bin"))) {
        echo 'cygwin not in path, appending environment variable'
        $env:PATH += ";C:\cygwin64\bin\";
    }
    iex -c 'C:\cygwin64\bin\bash.exe -c "source /home/ebrimah/.bashrc; /usr/local/bin/tig $arguments"';
}
# [Tig Integration With PowerShell (using Cygwin) - dahlbyk/posh-git GitHub Wiki](https://github-wiki-see.page/m/dahlbyk/posh-git/wiki/Tig-Integration-With-PowerShell-(using-Cygwin))

#-------------------------------    Functions END     -------------------------------





#-------------------------------   Set Alias BEGIN    -------------------------------
# 1. 编译函数 make
function MakeThings {
	nmake.exe $args -nologo
}
Set-Alias -Name make -Value MakeThings

# 2. 更新系统 os-update
Set-Alias -Name os-update -Value Update-Packages

# 3. 查看目录 ls & ll
function ListDirectory {
	(Get-ChildItem).Name
	Write-Host("")
}
#Set-Alias -Name ls -Value ListDirectory
#Set-Alias -Name ll -Value Get-ChildItem

# 4. 打开当前工作目录
function OpenCurrentFolder {
	param
	(
		# 输入要打开的路径
		# 用法示例：open C:\
		# 默认路径：当前工作文件夹
		$Path = '.'
	)
	Invoke-Item $Path
}
Set-Alias -Name open -Value OpenCurrentFolder

# 自定义方程LSC，数列形式展示文件
function lsc {
    Param ([int]$c = 5)
    ls | Format-Wide -Column $c -Property Name
}

#function GitLogPretty {
function glp {
  git fetch
  git log --graph --pretty='%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --all
}



## 终端命令行查英语单词
# function  {}
function  fanyi {
    declare q="$*";
    #curl --user-agent curl "https://v2en.co/${q// /%20}";
    curl --user-agent curl "https://d.supjohn.com/${q// /%20}";
}

#-------------------------------    Set Alias END     -------------------------------





#-------------------------------   Set Network BEGIN    -------------------------------
# 1. 获取所有 Network Interface
function Get-AllNic {
	Get-NetAdapter | Sort-Object -Property MacAddress
}
Set-Alias -Name getnic -Value Get-AllNic

# 2. 获取 IPv4 关键路由
function Get-IPv4Routes {
	Get-NetRoute -AddressFamily IPv4 | Where-Object -FilterScript {$_.NextHop -ne '0.0.0.0'}
}
Set-Alias -Name getip -Value Get-IPv4Routes

# 3. 获取 IPv6 关键路由
function Get-IPv6Routes {
	Get-NetRoute -AddressFamily IPv6 | Where-Object -FilterScript {$_.NextHop -ne '::'}
}
Set-Alias -Name getip6 -Value Get-IPv6Routes

# git命令简写
function gf {
    git fetch
}


Register-ArgumentCompleter -CommandName ssh,scp,sftp -Native -ScriptBlock {
    param($wordToComplete, $commandAst, $cursorPosition)
    $lstHosts = Get-Content ~\.ssh\config|%{ if ($_.trim() -match "^Host\s[\w|_|\d|-]*$") {$_.ToString().Trim().split(" ")[1]}}
    foreach ($val in $lstHosts) {
        if ($val -like "$wordToComplete*") {
            $val
        }
    }
}

function connect-ssh(){
    Get-Content ~\.ssh\config|%{ if ($_.trim() -match "^Host\s[\w|_|\d|-]*$") {$_.ToString().Trim().split(" ")[1]}}|fzf|%{ssh $_}
}